/***********************************************************************************************//**
*\n  @file       app_lan.c
*\n  @brief      以太网收发模块，同上位机接口
*\n  @details
*\n -----------------------------------------------------------------------------------
*\n  文件说明：
*\n       1.  以太网收发模块，同上位机接口
*\n       2.  合并之前StarSim_IP的代码；
*\n
*\n -----------------------------------------------------------------------------------
*\n  版本:    修改人:       修改日期:          描述:
*\n  V0.01  罗先能        2021.6.11           创建
*\n
***************************************************************************************************/


/**************************************************************************************************
* 头文件
***************************************************************************************************/
//#include <stdio.h>
//#include <stdlib.h>
//#include <pthread.h>
//#include <unistd.h>
//#include <string.h>
//#include <netinet/in.h>

#include "framework.h"
#include "app_lan.h"
#include "MTRT_SNInfoAPI.h"

#undef   DEBUG_LEVEL
#define  DEBUG_LEVEL  5
#include "vdebug.h"


/**************************************************************************************************
* 宏定义、结构定义
***************************************************************************************************/
#define MAXLINE 80
#define SERV_PORT 1060


/**************************************************************************************************
* 全局变量声明、定义
***************************************************************************************************/


/**************************************************************************************************
* 私有变量声明、定义
***************************************************************************************************/


/**************************************************************************************************
* 私有函数声明、定义
***************************************************************************************************/
#if 2
//
// Created by deeptuuk on 2019/11/27.
//
static void perr_exit(const char *s)
{
    perror(s);
    exit(1);
}

static int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr)
{
    int n;
    again:
    if ( (n = accept(fd, sa, salenptr)) < 0) {
        if ((errno == ECONNABORTED) || (errno == EINTR))
            goto again;
        else
            perr_exit("accept error");
    }
    return n;
}

static void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
    if (bind(fd, sa, salen) < 0)
        perr_exit("bind error");
}

static void Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
    if (connect(fd, sa, salen) < 0)
        perr_exit("connect error");
}

static void Listen(int fd, int backlog)
{
    if (listen(fd, backlog) < 0)
        perr_exit("listen error");
}

static int Socket(int family, int type, int protocol)
{
    int n;
    if ( (n = socket(family, type, protocol)) < 0)
        perr_exit("socket error");
    return n;
}

static ssize_t Read(int fd, void *ptr, size_t nbytes)
{
    ssize_t n;
    again:
    if ( (n = read(fd, ptr, nbytes)) == -1) {
        if (errno == EINTR)
            goto again;
        else
            return -1;
    }
    return n;
}

static ssize_t Write(int fd, const void *ptr, size_t nbytes)
{
    ssize_t n;
    again:
    if ( (n = write(fd, ptr, nbytes)) == -1) {
        if (errno == EINTR)
            goto again;
        else
            return -1;
    }
    return n;
}

static void Close(int fd)
{
    if (fd != -1)
    	close(fd);
        //perr_exit("close error");
}

static ssize_t Readn(int fd, void *vptr, size_t n)
{
    size_t nleft;
    ssize_t nread;
    char* ptr;
    ptr = vptr;
    nleft = n;

    while (nleft > 0) {
        if ( (nread = read(fd, ptr, nleft)) < 0) {
            if (errno == EINTR)
                nread = 0;
            else
                return -1;
        }
        else if (nread == 0) {
            break;
        }
        nleft -= nread;
        ptr += nread;
    }

    return n - nleft;
}

static ssize_t Writen(int fd, const void *vptr, size_t n)
{
    size_t nleft;
    ssize_t nwritten;
    const char *ptr;
    ptr = vptr;
    nleft = n;

    while (nleft > 0) {
        if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
            if (nwritten < 0 && errno == EINTR)
                nwritten = 0;
            else
                return -1;
        }
        nleft -= nwritten;
        ptr += nwritten;
    }
    return n;
}


//UDP线程，查询IP地址
static void *thr_fn_udp(void *arg)
{
	char str_1[] = "StarSim_IP";               // 上位机发送的查询命令
	char str_2[] = "StarSim_IP_confirm";       // 下位机的应答

	struct sockaddr_in servaddr, cliaddr;
	socklen_t cliaddr_len;
	int sockfd;
	char buf[MAXLINE];
	char str[INET_ADDRSTRLEN];
	int i, n;

	sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(SERV_PORT);

	Bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

	printf("Accepting UDP connections ...\n");

	while(1) {
		cliaddr_len = sizeof(cliaddr);
		n = recvfrom(sockfd, buf, MAXLINE, 0, (struct sockaddr *)&cliaddr, &cliaddr_len);
		if (n == -1)
			perr_exit("recvfrom error");
		printf("received from %s at PORT %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port));
		printf("test:%s\n", buf);

		// 1.查询IP地址
		if(strcmp(buf, str_1) == 0){
			printf("test: equal\n");
			n = sendto(sockfd, str_2, 18, 0, (struct sockaddr *)&cliaddr, sizeof(cliaddr));
		}
	}

	return (void *)0;
}



int GetFilename(char *tmpFile, int flags, char **ppFile)
{
	static char buf[1024];
	static int  iFlags = 0;
	static char *pTop    = buf;
	static char *pBottom = buf;

	int  ret = 0;

	if (flags == 0)   // 读取文件
	{
		memset(buf, 0, sizeof(buf));
		pTop = pBottom = buf;
		FILE *pFile = fopen(tmpFile, "r");
		if (pFile == NULL)
		{
			iFlags = 0;
			return -1;
		}
		fread(buf, sizeof(buf), 1, pFile);
		fclose(pFile);
		iFlags = 1;
		return 0;
	}
	else if ((1 == flags) && (1 == iFlags))   // 解析数据
	{
		pBottom = strchr(pTop, 0x0a);
		if (NULL == pBottom)
		{
			iFlags = 0;
			return -1;
		}

		*pBottom = '\0';
		*ppFile = pTop;      // 返回字符串
		pTop = pBottom + 1;  // 指向下一个字符串
		return 0;
	}
	return -1;
}


// tcp线程，修改静态IP地址；
static void *thr_fn_tcp(void *arg)
{
	int ret;
	static char str_1[] = "modify";            // 1. 设置静态IP
	static char str_2[] = "confirm_modify";

	static char str_get_dna[] ="get_dna";      // 2. 读取DNA， 返回dna的字符串
	static char check_dna[] ="check_dna";      // 3. 校验DNA， 返回“ok” 或者 “error”


	struct sockaddr_in servaddr, cliaddr;
	socklen_t cliaddr_len;
	int listenfd, connfd;
	char buf[MAXLINE];
	char str[INET_ADDRSTRLEN];
	int i, n;

	listenfd = Socket(AF_INET, SOCK_STREAM, 0);
	int iOptionVal = 1;
	setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &iOptionVal, sizeof(iOptionVal));

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(SERV_PORT);

	Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
	Listen(listenfd, 20);
	printf("Accepting TCP connections ...\n");

	while(1)
	{
		Close(connfd);
		cliaddr_len = sizeof(cliaddr);
		connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);

		while(1) {
			memset(buf, 0, sizeof(buf));
			n = Read(connfd, buf, MAXLINE);
			if (n == 0) {
				printf("the other side has been closed.\n");
				break;
			}
			printf("recv:%s\n", buf);

			/*
			** 1. 设置静态ip地址并重启
			*/
			if(strcmp(buf, str_1) == 0)
			{
				printf("recive ok\n");
				Write(connfd, str_2, 15);
				n = Read(connfd, buf, MAXLINE);
				if (n == 0) {
					printf("the other side has been closed.\n");
					break;
				}
				printf("recive:%s\n", buf);

				FILE *fp = NULL;
				fp = fopen("/etc/init.d/StarSim_IP", "w+");
				fprintf(fp,"%s \n", buf);
				fclose(fp);
				system("sync");
				system("reboot");
			}

			/*
			** 2. 读取DNA
			**    <1>接收命令"get_dna"
			**    <2>下载fpgabit文件
			**    <3>读取dna，并返回给上位机
			*/
			else if(strcmp(buf, str_get_dna) == 0)
			{
				ret = HwOpen(DEV_NO_DNA, NULL);
				system("cat /home/test_dna.bit > /dev/xdevcfg");
				//ret = HwLoad(DEV_NO_DNA, "/home/test_dna.bit");      // 下载fpga文件
				HwClose(DEV_NO_DNA, NULL);
				if (ret < 0)
				{
					debug_error("HwLoad(DEV_NO_DNA) < 0\n");
					continue;
				}
				printf("load /home/test_dna.bit ok \n");

				u32 dnal,dnah;
				u64 value;
				ret = HwRead(DEV_NO_DNA, 14*4, &dnal, sizeof(dnal)); // 读取DNA
				ret = HwRead(DEV_NO_DNA, 15*4, &dnah, sizeof(dnah));

				value = dnah;
				value = (value << 32) + dnal;
				memset(buf, 0, sizeof(buf));
				snprintf(buf, sizeof(buf), "%llu", value);
				printf("fpga DNA: %llu\n", value);
				Write(connfd, buf, strlen(buf));                     // 返回DNA
			}

			/*
			** 3. 校验DNA， 返回“<file>:ok” 或者 “<file>:error”
			*/
			else if(strcmp(buf, check_dna) == 0)
			{
				SNLineInfo  tInfo = {0};
				char * pInFile = NULL;

				ret = HwOpen(DEV_NO_DNA, NULL);
				system("cat /home/test_dna.bit > /dev/xdevcfg");
				//ret = HwLoad(DEV_NO_DNA, "/home/test_dna.bit");      // 下载fpga文件
				HwClose(DEV_NO_DNA, NULL);
				if (ret < 0)
				{
					debug_error("HwLoad(DEV_NO_DNA) < 0\n");
					continue;
				}
				printf("load /home/test_dna.bit ok \n");

				// 将ls *.dat文件输出到/tmp/tmp1060.txt文件
				system("ls --color=none /home/*.dat > /tmp/tmp1060.txt");
				GetFilename("/tmp/tmp1060.txt", 0, NULL);
				while(GetFilename(NULL, 1, &pInFile) == 0)
				{
					debug_printf("file: %s\n", pInFile);
					if(pInFile == NULL)
						continue;

					tInfo = MTReadSNDat(pInFile);
					u32 pid = tInfo.ProductID;
					u32 keyh = (u32)(tInfo.FPGASN >> 32);
					u32 keyl = (u32)tInfo.FPGASN;
					u32 result = 0;
					HwWrite(DEV_NO_DNA, (16+7)*4, &pid,	4);
					HwWrite(DEV_NO_DNA, (16+14)*4, &keyl, 4);
					HwWrite(DEV_NO_DNA, (16+15)*4, &keyh, 4);

					sleep(5);
					ret = HwRead(DEV_NO_DNA, 13*4, &result, 4);  // 读取结果
					if (ret < 0)
					{
						debug_error("HwRead(DEV_NO_DNA) < 0\n");
						continue;
					}
					printf("DNA Check %s == %d \n", pInFile, result);

					memset(buf, 0, sizeof(buf));
					strcpy(buf, pInFile);
					if(result == 1)
						strcat(buf, ":ok\n");
					else
						strcat(buf, ":error\n");
					Write(connfd, buf, strlen(buf));     // 返回DNA
				}
			}
		}
	}
	return (void *)0;
}


#endif

/**************************************************************************************************
* 全局函数声明、定义
***************************************************************************************************/

// 启动Tcp/IP线程
// 启动Udp/IP线程
int AppLanStart(int argc, char *argv[])
{
	pthread_t udp_t;
	pthread_t tcp_t;

	pthread_create(&udp_t, NULL, thr_fn_udp, NULL);
	pthread_create(&tcp_t, NULL, thr_fn_tcp, NULL);

	pthread_join(udp_t, NULL);
	pthread_join(tcp_t, NULL);
	return 0;
}


